import random
import car
import util
from basicNode import basicNode
import time
import config

class node(basicNode):
    
    @staticmethod
    def fromBasicNode(basicNode):
        """Create a node from a basicNode instance."""
        result = node()
        for key in basicNode.__dict__:
            setattr(result,key,basicNode.__dict__[key])
        result.tempPriority = basicNode.priority
        return result
        

    def __init__(self,x = 0.,y = 0. ,ID = None ,isSafeNode = False,\
    hasLights = False):            
        """
        Create new node instance. 
        
        Keyword arguments:
        x -- x position of the node (default 0.0 )
        y -- y position of the node (default 0.0 )        
        ID -- id (name) of the node,
        isSafeNode -- binary flag, saying whether a node is the safe node. 
        Generally car won't move unless it has free way to the next safe node.
        hasLights -- binary flag, saying whether a node has lights. 
        """
        basicNode.__init__(self,x,y,ID,isSafeNode,hasLights)
        self.reservation = None
        self.isSomeoneInside = None
        self.numberOfLightCycles = -2
        self.tempPriority = 1
        self.queue = []

    def cancelReservation(self):
        """
        Cancel all of the reservations made on this node as well as the 
        information whether there is a car in this node. 
        """
        self.reservation = None
        self.isSomeoneInside = None
        self.queue = []
    
    
    def makeReservation(self,car):
        """
        Try to make a reservation on this node by a car. Return True if the car 
        which holds the reservation after this step will go to this node 
        through the same edge as the car given in argument (e.g. if the 
        reservation was successful the answer will be True).
        
        Keep in mind that even if a car successfully makes an reservation, it 
        still can be overwritten in the same round by another car.
        """
        if self.reservation == None:
            self.reservation = car
        else:
            isAfterOld = self.reservation.isAfterSafeNode(self)
            isAfterNew = car.isAfterSafeNode(self)                                            
            
            if not isAfterOld and isAfterNew:
                pass
            elif self.reservation.lastSafeNode.tempPriority >\
            car.lastSafeNode.tempPriority :
                pass
            elif self.reservation.lastSafeNode.tempPriority <\
             car.lastSafeNode.tempPriority :
                self.queue.append( self.reservation )
                self.reservation = car
            else:
                pair1 = car.route.getPairOfEdges(self)
                pair2 = self.reservation.route.getPairOfEdges(self)
                if pair1 == pair2:
                    pass
                elif self.goesFirst(pair1,pair2):
                    self.reservation = car        
                    self.queue.append( self.reservation )
                    self.reservation = car

            if isAfterOld and not isAfterNew and not\
            car.route.getEdge(self) ==  self.reservation.route.getEdge(self):
                self.queue.append( self.reservation )
                self.reservation = car
                self.reservation.jumpedIntoTheQueue.add(self)
                print 1
            
        return car.route.getEdge(self) ==  self.reservation.route.getEdge(self)

    def revertReservation(self,car):
        if self.reservation == car:
            if len( self.queue ) > 0:
                self.reservation = self.queue.pop()
            else:
                self.reservation.queue = None

    def goesFirst(self, pair1, pair2):
        """
        Arguments of this function are two pairs of edges. Each pair of the 
        edges consists of edge going to this node and an edge going out of this 
        node. Each pair is a fragment of route. 
        """
        p11 = (pair1[0].startNode.getXY(), pair1[0].endNode.getXY() ) 
        p12 = (pair1[1].startNode.getXY(), pair1[1].endNode.getXY() )         
        p1 = (p11, p12)
        
        p21 = (pair2[0].startNode.getXY(), pair2[0].endNode.getXY() ) 
        p22 = (pair2[1].startNode.getXY(), pair2[1].endNode.getXY() ) 
        p2 = (p21, p22)
        
        return not util.isRight(p1, p2)
               
    def checkColision(self,car):
        """
        Check whether a car given in argument can go safely (e.g. without 
        collision with another car) to this node.
        """
        if self.isRedLight:
            return False
        if self.isSomeoneInside is not None:
            if self.isSomeoneInside == car:
                return True
            elif util.areLocalRoutesEqual( self.isSomeoneInside.route, 
                car.route, self):
                if self.reservation is None:
                    return False
                else:
                    return self.reservation.route.getEdge(self) ==\
                        car.route.getEdge(self)
        else:
            if self.reservation is None:
                return False
            return self.reservation.route.getEdge(self) ==\
                car.route.getEdge(self)


    def addRouteToQueue(self, route):
        """
        Add a car to a queue of cars that are waiting in this node to appear.
        """
        self.queue.append(route)
    
    def addCarFromQueue(self):
        """
        Checked whether a car from queue can be placed in this node. Whenever 
        there is no car in this node and and there is no reservation on this 
        node a first car from the queue is placed in this node. 
        """
        if len(self.queue) > 0:
            route = self.queue[0]
            if (self.isSomeoneInside is None) and (self.reservation is None):
                del self.queue[0]
                return car.car(route.listOfEdges[0], 0 ,0.001, route , self)
            else:
                return None
        else:
            return None

    def changeLights(self, deltaTime):
        """
        Check whether lights should be changed and change them if yes. 
        """
        if not self.hasLights:
            return
        eps =  self.redLightPhase + self.greenLightPhase  
        if self.isRedLight:
            if deltaTime - (self.numberOfLightCycles + 1) * eps - self.startEps >  0:
                self.isRedLight = False
                self.update()
        else:
            if deltaTime - (self.numberOfLightCycles + 1) * eps - self.startEps - self.greenLightPhase >  0:
                self.numberOfLightCycles += 1
                self.isRedLight = True
                self.update()
            
            
    def update(self):
        """
        Change the priority of this node, appropriately to the current state of
        lights. 
        """
        if self.isRedLight:
            self.tempPriority = 10
        else:
            self.tempPriority = 1
